home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 7 / Amiga Format AFCD07 (Dec 1996, Issue 91).iso / serious / shareware / comms / internet / html-related / hsc / source / hsclib / parse.c < prev    next >
C/C++ Source or Header  |  1996-08-31  |  31KB  |  1,099 lines

  1. /*
  2.  * hsclib/parse.c
  3.  *
  4.  * parse file: handle for entities & tags
  5.  *
  6.  * Copyright (C) 1995,96  Thomas Aglassinger
  7.  *
  8.  * This program is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; either version 2 of the License, or
  11.  * (at your option) any later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  * GNU General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU General Public License
  19.  * along with this program; if not, write to the Free Software
  20.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  *
  22.  * updated: 31-Aug-1996
  23.  * created:  1-Jul-1995
  24.  *
  25.  */
  26.  
  27. #define NOEXTERN_HSCLIB_PARSE_H
  28.  
  29. #include "hsclib/inc_base.h"
  30.  
  31. #include "hsclib/defattr.h"
  32. #include "hsclib/deftag.h"
  33. #include "hsclib/idref.h"
  34. #include "hsclib/include.h"
  35. #include "hsclib/input.h"
  36. #include "hsclib/parse.h"
  37. #include "hsclib/posteval.h"
  38. #include "hscprj/project.h"
  39. #include "hsclib/skip.h"
  40. #include "hsclib/size.h"
  41. #include "hsclib/uri.h"
  42.  
  43. /*
  44.  *---------------------------
  45.  * misc. functions
  46.  *---------------------------
  47.  */
  48.  
  49. /*
  50.  * message_rplc
  51.  *
  52.  * message that tells user that a special char
  53.  * was replaced by its entity
  54.  */
  55. static VOID message_rplc(HSCPRC * hp, STRPTR what, STRPTR by)
  56. {
  57.     hsc_message(hp, MSG_RPLC_ENT,
  58.                 "replaced %q by %q", what, by);
  59. }
  60.  
  61. /*
  62.  * check_mbinaw
  63.  *
  64.  * check if tag occures at a allowed position
  65.  */
  66. static BOOL check_mbinaw(HSCPRC * hp, HSCTAG * tag)
  67. {
  68.     BOOL ok = TRUE;
  69.  
  70.     /* check for tags that must be called before */
  71.     if (tag->mbi)
  72.     {
  73.         DLNODE *nd = hp->container_stack->first;
  74.         LONG found = 0;
  75.  
  76.         while (nd && !found)
  77.         {
  78.             HSCTAG *ctag = (HSCTAG *) nd->data;
  79.  
  80.             found = strenum(ctag->name, tag->mbi, '|', STEN_NOCASE);
  81.             nd = nd->next;
  82.  
  83.         }
  84.  
  85.         if (!found)
  86.         {
  87.             hsc_message(hp, MSG_MBI,
  88.                         "%T must be inside %t", tag, tag->mbi);
  89.             ok = FALSE;
  90.         }
  91.     }
  92.  
  93.     /* check for tags that are not to be called before */
  94.     if (tag->naw)
  95.     {
  96.         DLNODE *nd = hp->container_stack->first;
  97.         LONG found = 0;
  98.  
  99.         while (nd)
  100.         {
  101.             HSCTAG *ctag = (HSCTAG *) nd->data;
  102.  
  103.             found = strenum(ctag->name, tag->naw, '|', STEN_NOCASE);
  104.             if (found)
  105.             {
  106.                 hsc_message(hp, MSG_NAW,
  107.                             "%T not allowed within %C", tag, ctag);
  108.                 ok = FALSE;
  109.             }
  110.             nd = nd->next;
  111.         }
  112.     }
  113.     return (ok);
  114. }
  115.  
  116. /* enable output for a process */
  117. static void hp_enable_output(HSCPRC * hp, STRPTR cause)
  118. {
  119.     if (hp->suppress_output)
  120.     {
  121.         D(fprintf(stderr, DHL "output enabled (%s)\n", cause));
  122.     }
  123.     hp->suppress_output = FALSE;
  124. }
  125.  
  126. /*
  127.  *---------------------------
  128.  * remove/append end tag
  129.  * from/to container_stack
  130.  *---------------------------
  131.  */
  132.  
  133. /*
  134.  * app_ctag
  135.  *
  136.  * create end tag and append it to tag-list;
  137.  * also clone options & attribute list of parent
  138.  * tag, if tag is a macro and has a closing tag.
  139.  *
  140.  * params: hp.....hscprc with container_stack to be modified
  141.  *         tagid..name of the new tag (eg "IMG")
  142.  * result: ptr to the new tag or NULL if no mem
  143.  */
  144. HSCTAG *app_ctag(HSCPRC * hp, HSCTAG * tag)
  145. {
  146.     HSCTAG *ctag;
  147.     DLLIST *taglist = hp->container_stack;
  148.  
  149.     ctag = new_hsctag(tag->name);
  150.     if (ctag)
  151.     {
  152.         BOOL ok = TRUE;
  153.         DLNODE *nd = NULL;
  154.  
  155.         /* copy important data of tag */
  156.         ctag->option = tag->option;
  157.  
  158.         /* clone attributes, if tag is a
  159.          * macro tag and has a closing tag
  160.          */
  161.         if ((tag->option & HT_MACRO)
  162.             && (tag->option & HT_CLOSE))
  163.         {
  164.             ok = copy_local_varlist(
  165.                                        ctag->attr, tag->attr, MCI_APPCTAG);
  166.         }
  167.         /* remeber position where start tag has been called */
  168.         /* (for message "end tag missing) */
  169.         ctag->start_fpos = new_infilepos(hp->inpf);
  170.  
  171.         /* insert tag in list */
  172.         if (ok)
  173.         {
  174.             nd = app_dlnode(taglist, ctag);
  175.             if (!nd)
  176.             {
  177.                 del_hsctag((APTR) ctag);
  178.                 ctag = NULL;
  179.             }
  180.         }
  181.     }
  182.     return (ctag);
  183. }
  184.  
  185. /*
  186.  * params: tagname..tag to remove
  187.  *         check....show messages
  188.  */
  189. VOID remove_ctag(HSCPRC * hp, HSCTAG * tag)
  190. {
  191.     /* search for tag on stack of occured tags */
  192.     DLNODE *nd = find_dlnode(hp->container_stack->first, (APTR) tag->name, cmp_strtag);
  193.     if (nd == NULL)
  194.     {
  195.         /* closing tag not found on stack */
  196.         /* ->unmatched closing tag without previous opening tag */
  197.         if (!(tag->option & HT_AUTOCLOSE))
  198.             hsc_message(hp, MSG_UNMA_CTAG, "unmatched %C ", tag);
  199.     }
  200.     else
  201.     {
  202.         /* closing tag found on stack */
  203.         HSCTAG *ctag = (HSCTAG *) nd->data;
  204.         STRPTR foundnm = (STRPTR) ctag->name;
  205.         STRPTR lastnm = (STRPTR) hp->container_stack->last->data;
  206.  
  207.         /* check if name of closing tag is -not- equal
  208.          * to the name of the last tag last on stack
  209.          * ->illegal tag nesting
  210.          */
  211.         if (upstrcmp(lastnm, foundnm)
  212.             && !(tag->option | HT_MACRO)
  213.             && !(is_hsc_tag(tag)))
  214.         {
  215.             hsc_message(hp, MSG_CTAG_NESTING,
  216.                         "illegal end tag nesting (expected %c, found %C)",
  217.                         lastnm, tag);
  218.         }
  219.  
  220.         /* if closing tag has any attributes defined,
  221.          * it must be a closing macto tag. so copy
  222.          * the attributes of the closing tag to the
  223.          * attributes of the macro tag. therefor,
  224.          * the closing macro tag inherits the
  225.          * attributes of his opening macro
  226.          */
  227.         if (ctag->attr)
  228.             set_local_varlist(tag->attr, ctag->attr, MCI_APPCTAG);
  229.  
  230.         /* remove node for closing tag from container_stack */
  231.         del_dlnode(hp->container_stack, nd);
  232.     }
  233. }
  234.  
  235. /*
  236.  *---------------------------
  237.  * parse tag functions
  238.  *---------------------------
  239.  */
  240.  
  241. /*
  242.  * hsc_parse_tag
  243.  *
  244.  * parse tag (after "<")
  245.  */
  246. BOOL hsc_parse_tag(HSCPRC * hp)
  247. {
  248.     INFILE *inpf = hp->inpf;
  249.     STRPTR nxtwd = NULL;
  250.     DLNODE *nd = NULL;
  251.     HSCTAG *tag = NULL;
  252.     ULONG tci = 0;              /* tag_call_id returned by set_tag_args() */
  253.     BOOL(*hnd) (HSCPRC * hp, HSCTAG * tag) = NULL;
  254.     BOOL open_tag;
  255.     DLLIST *taglist = hp->deftag;
  256.     BOOL rplc_lt = FALSE;       /* TRUE, if replace spc. char "<" */
  257.     BOOL hnd_result = TRUE;     /* result returned by handle */
  258.     BOOL unknown_tag = FALSE;   /* TRUE, if tag has not been defined before */
  259.  
  260.     /* init strings used inside tag-handles */
  261.     set_estr(hp->tag_name_str, infgetcw(inpf));
  262.     clr_estr(hp->tag_attr_str);
  263.     clr_estr(hp->tag_close_str);
  264.  
  265.     if (hp->smart_ent && strlen(infgetcws(inpf)))
  266.     {
  267.         /*
  268.          * check for special char "<"
  269.          */
  270.         int ch = infgetc(inpf);
  271.  
  272.         if (hsc_whtspc(ch))
  273.         {
  274.             rplc_lt = TRUE;
  275.  
  276.             /* write "<" and white spaces */
  277.             message_rplc(hp, "<", "<");
  278.             hsc_output_text(hp, infgetcws(inpf), "<");
  279.         }
  280.         inungetc(ch, inpf);
  281.     }
  282.  
  283.     if (!rplc_lt)
  284.     {
  285.         /* get tag id */
  286.         nxtwd = infget_tagid(hp);
  287.  
  288.         if (!hp->fatal)
  289.         {
  290.             /* append tag-name to tag_name_str */
  291.             app_estr(hp->tag_name_str, infgetcws(inpf));
  292.             app_estr(hp->tag_name_str, infgetcw(inpf));
  293.  
  294.             /* check for hsctag; if not, enable output */
  295.             if (hp->suppress_output
  296.                 && upstrncmp(nxtwd, HSC_TAGID, strlen(HSC_TAGID))
  297.                 && strcmp(nxtwd, HSC_COMMENT_STR)
  298.                 && strcmp(nxtwd, HSC_ONLYCOPY_STR)
  299.                 )
  300.             {
  301.                 hp_enable_output(hp, "non-hsctag occured");
  302.             }
  303.  
  304.             if (!hp->suppress_output)
  305.             {
  306.                 D(fprintf(stderr, DHL "tag <"));
  307.             }
  308.         }
  309.     }
  310.  
  311.     if (!hp->fatal && !rplc_lt)
  312.     {
  313.         BOOL write_tag = FALSE; /* flag: write tag text & attrs to output? */
  314.  
  315.         if (strcmp("/", nxtwd)) /* is it a closing tag? */
  316.         {
  317.             /*
  318.              *
  319.              * process start-tag
  320.              *
  321.              */
  322.             open_tag = TRUE;
  323.             if (!hp->suppress_output)
  324.             {
  325.                 D(fprintf(stderr, "%s>\n", nxtwd));
  326.             }
  327.             /* search for tag in list */
  328.             nd = find_dlnode(taglist->first, (APTR) nxtwd, cmp_strtag);
  329.             if (nd == NULL)
  330.             {
  331.                 hsc_message(hp, MSG_UNKN_TAG,   /* tag not found */
  332.                             "unknown %t", nxtwd);
  333.                 tag = new_hsctag(nxtwd);
  334.                 tag->option |= HT_UNKNOWN;
  335.                 unknown_tag = TRUE;
  336. #if 0
  337.                 /* NOTE: This one's a bit perverted, because
  338.                  * the closing ">" is appended to the
  339.                  * attribute string, and the closing string
  340.                  * is left empty; as there is nearly no code
  341.                  * between setting and writing the strings,
  342.                  * I think this is more reasonable than doing
  343.                  * some tricky string-manipulation...
  344.                  */
  345.                 skip_until_eot(hp, hp->tag_attr_str);
  346.                 clr_estr(hp->tag_close_str);
  347. #endif
  348.             }
  349.             else
  350.             {
  351.                 tag = (HSCTAG *) nd->data;
  352.             }
  353.  
  354.             /* set handle-function */
  355.             hnd = tag->o_handle;
  356.  
  357.             /*
  358.              * handle options
  359.              */
  360.  
  361.             /* check for obsolete tag */
  362.             if (tag->option & HT_OBSOLETE)
  363.             {
  364.                 hsc_message(hp, MSG_TAG_OBSOLETE,
  365.                             "%T is obsolete", tag);
  366.             }
  367.  
  368.             /* check for jerk-tag */
  369.             if (tag->option & HT_JERK)
  370.             {
  371.                 hsc_message(hp, MSG_TAG_JERK,
  372.                             "%T is only used by jerks", tag);
  373.             }
  374.  
  375.             /* only-once-tag occured twice? */
  376.             if ((tag->option & HT_ONLYONCE) && (tag->occured))
  377.             {
  378.                 hsc_message(hp, MSG_TAG_TOO_OFTEN,
  379.                             "%T occured too often", tag);
  380.             }
  381.  
  382.             /* set occured-flag */
  383.             if (tag->option & (HT_ONLYONCE | HT_REQUIRED))
  384.                 tag->occured = TRUE;
  385.  
  386.             /* check for "must be inside"/"not allowed within"-tags */
  387.             if (!check_mbinaw(hp, tag))
  388.                 hnd = NULL;
  389.  
  390.             /* clear (reset to default) attribute values of tag */
  391.             clr_varlist(tag->attr);
  392.  
  393.             /* set attributes or check for ">" */
  394.             if (!(tag->option & HT_SPECIAL))
  395.             {
  396.                 tci = set_tag_args(hp, tag);
  397.                 if (tci == MCI_ERROR)
  398.                 {
  399.                     skip_until_eot(hp, NULL);
  400.                     hnd = NULL;
  401.                 }
  402.  
  403.                 if (!hp->fatal)
  404.                 {
  405.                     /* set ">" in string that contains closing text */
  406.                     set_estr(hp->tag_close_str, infgetcws(inpf));
  407.                     set_estr(hp->tag_close_str, infgetcw(inpf));
  408.  
  409.                     /* check for succeeding white-space */
  410.                     if ((tag->option & HT_WHTSPC)
  411.                         && !infeof(inpf))
  412.                     {
  413.                         int ch = infgetc(inpf);
  414.  
  415.                         if ((ch == ' ')
  416.                             || (ch == '\n')
  417.                             || (ch == '\t'))
  418.                         {
  419.                             hsc_message(hp, MSG_SUCC_WHTSPC,
  420.                                         "succeeding white-space for %T",
  421.                                         tag);
  422.                         }
  423.                         inungetc(ch, inpf);
  424.                     }
  425.                 }
  426.             }
  427.  
  428.             /* end-tag required? */
  429.             if (tag->option & HT_CLOSE)
  430.                 app_ctag(hp, tag);
  431.         }
  432.         else
  433.         {
  434.             /*
  435.              *
  436.              * process end-tag
  437.              *
  438.              */
  439.  
  440.             /* get tag id */
  441.             nxtwd = infget_tagid(hp);   /* get tag id */
  442.             open_tag = FALSE;
  443.  
  444.             /* append tag-name to tag_name_str */
  445.             app_estr(hp->tag_name_str, infgetcws(inpf));
  446.             app_estr(hp->tag_name_str, infgetcw(inpf));
  447.  
  448.             if (!hp->suppress_output)
  449.             {
  450.                 D(fprintf(stderr, "/%s>\n", nxtwd));
  451.             }
  452.             /* search for tag in taglist */
  453.             /* (see if it exists at all) */
  454.             nd = find_dlnode(taglist->first, (APTR) nxtwd, cmp_strtag);
  455.             if (nd == NULL)
  456.             {
  457.                 /* closing tag is absolutely unknown */
  458.                 hsc_message(hp, MSG_UNKN_TAG,   /* tag not found */
  459.                             "unknown %c", nxtwd);
  460.                 skip_until_eot(hp, hp->tag_attr_str);
  461.             }
  462.             else
  463.             {
  464.                 tag = (HSCTAG *) nd->data;      /* fitting tag in taglist */
  465.  
  466.                 /* check for preceding white-spaces */
  467.                 if ((tag->option & HT_WHTSPC) && hp->preceding_whtspc)
  468.                 {
  469.                     hsc_message(hp, MSG_PREC_WHTSPC,
  470.                                 "preceding white-space for %C",
  471.                                 tag);
  472.                 }
  473.  
  474.                 if (tag->option & (HT_CLOSE | HT_AUTOCLOSE))
  475.                 {
  476.                     /* set closing handle */
  477.                     hnd = tag->c_handle;
  478.  
  479.                     /* check for no args */
  480.                     if (!parse_wd(hp, ">"))
  481.                     {
  482.                         hsc_message(hp, MSG_CL_TAG_ARG,
  483.                                     "no attributes allowed for end-tags");
  484.                     }
  485.                     else
  486.                     {
  487.                         /* set ">" in string that contains closing text */
  488.                         set_estr(hp->tag_close_str, infgetcws(inpf));
  489.                         app_estr(hp->tag_close_str, infgetcw(inpf));
  490.                     }
  491.  
  492.                     /* set values of attributes stored
  493.                      * in end-tag,
  494.                      * remove end-tag from stack
  495.                      */
  496.                     remove_ctag(hp, tag);
  497.                 }
  498.                 else
  499.                 {
  500.                     /* illegal closing tag */
  501.                     hsc_message(hp, MSG_ILLG_CTAG,      /* tag not found */
  502.                                 "illegal %c", nxtwd);
  503.                     parse_gt(hp);
  504.                     tag = NULL;
  505.                 }
  506.             }
  507.         }
  508.  
  509.         /*
  510.          * processed for opening AND closing tag
  511.          */
  512.         write_tag = (!(tag) || !(tag->option & HT_NOCOPY));
  513.  
  514.         if (tag)
  515.         {
  516.             /*
  517.              * check if tag should be stripped
  518.              */
  519.             if (!postprocess_tagattr(hp, tag, open_tag))
  520.             {
  521.                 /* stripped tag with external reference */
  522.                 if (open_tag)
  523.                     hsc_msg_stripped_tag(hp, tag, "external reference");
  524.                 hnd = NULL;     /* don't call handle */
  525.                 write_tag = FALSE;      /* don't output tag */
  526.             }
  527.             else if (hp->strip_tags
  528.                      && strenum(tag->name, hp->strip_tags, '|', STEN_NOCASE))
  529.             {
  530.                 /* strip tag requested by user */
  531.                 if (!(tag->option & HT_SPECIAL))
  532.                 {
  533.                     if (open_tag)
  534.                         hsc_msg_stripped_tag(hp, tag, "as requested");
  535.                     hnd = NULL; /* don't call handle */
  536.                     write_tag = FALSE;  /* don't output tag */
  537.                 }
  538.                 else
  539.                 {
  540.                     hsc_message(hp, MSG_TAG_CANT_STRIP,
  541.                                 "can't strip special tag %T", tag);
  542.                 }
  543.  
  544.                 /*
  545.                  * get values for size from reference
  546.                  */
  547.             }
  548.             else if (tag->uri_size && get_vartext(tag->uri_size))
  549.                 get_attr_size(hp, tag);
  550.         }
  551.  
  552.         /* call handle if available */
  553.         if (hnd && !hp->fatal)
  554.             hnd_result = (*hnd) (hp, tag);
  555.  
  556.         /* write whole tag out */
  557.         if (write_tag && hnd_result)
  558.         {
  559.             VOID(*tag_callback) (struct hscprocess * hp,
  560.                                  HSCTAG * tag,
  561.                  STRPTR tag_name, STRPTR tag_attr, STRPTR tag_close) = NULL;
  562.  
  563.             if (open_tag)
  564.                 tag_callback = hp->CB_start_tag;
  565.             else
  566.                 tag_callback = hp->CB_end_tag;
  567.  
  568.             if (tag_callback)
  569.             {
  570.                 (*tag_callback) (hp, tag,
  571.                                  estr2str(hp->tag_name_str),
  572.                                  estr2str(hp->tag_attr_str),
  573.                                  estr2str(hp->tag_close_str));
  574.             }
  575.         }
  576.  
  577.         /* skip LF if requested */
  578.         if (tag && (tag->option & HT_SKIPLF))
  579.             skip_lf(hp);
  580.  
  581.         /* remove temporary created tag */
  582.         if (unknown_tag)
  583.             del_hsctag(tag);
  584.     }
  585.  
  586.     return (BOOL) (!hp->fatal);
  587. }
  588.  
  589. /*
  590.  *---------------------------
  591.  * other parse functions
  592.  *---------------------------
  593.  */
  594.  
  595. /* replace icon-entity by image */
  596. static VOID replace_icon(HSCPRC * hp, STRPTR icon)
  597. {
  598.     INFILEPOS *base = new_infilepos(hp->inpf);
  599.     EXPSTR *image = init_estr(0);
  600.  
  601.     /* create string like <IMG SRC=":icons/back.gif" ALT="back"> */
  602.     set_estr(image, "<IMG SRC=\"");
  603.     estrcat(image, hp->iconbase);
  604.  
  605.     /* check, if iconbase contains "*" */
  606.     if (strchr(estr2str(hp->iconbase), '*'))
  607.     {
  608.         STRPTR s = estr2str(hp->iconbase);
  609.  
  610.         while(s[0])
  611.         {
  612.             if (s[0] =='*')
  613.                 app_estr(image, icon);
  614.             else
  615.                 app_estrch(image, s[0]);
  616.             s++;
  617.         }
  618.     }
  619.     else
  620.     {
  621.         app_estr(image, icon);
  622.         app_estr(image, ".gif");
  623.     }
  624.         app_estr(image, "\" ALT=\"");
  625.         app_estr(image, icon);
  626.         app_estr(image, "\">");
  627.  
  628.     hsc_message(hp, MSG_RPLC_ICON, "replacing icon-%e", icon);
  629.  
  630.     hsc_include_string(hp, SPECIAL_FILE_ID "include icon",
  631.                        estr2str(image),
  632.                        IH_PARSE_HSC | IH_NO_STATUS | IH_POS_PARENT);
  633.     del_estr(image);
  634.     del_infilepos(base);
  635. }
  636.  
  637. /*
  638.  * hsc_parse_amp
  639.  *
  640.  * parse ampersand ("&")
  641.  */
  642. BOOL hsc_parse_amp(HSCPRC * hp)
  643. {
  644.     INFILE *inpf = hp->inpf;
  645.     EXPSTR *amp_str = init_estr(0);
  646.  
  647.     if (!hp->fatal)
  648.     {
  649.         BOOL rplc = hp->smart_ent;      /* TRUE, if "&" should be replaced */
  650.  
  651.         hp_enable_output(hp, "entity");
  652.  
  653.         if (rplc)
  654.         {
  655.             /*
  656.              * test if char before and
  657.              * after ">" is white-space
  658.              */
  659.             int ch = infgetc(inpf);
  660.  
  661.             inungetc(ch, inpf);
  662.  
  663.             if (!(hsc_whtspc(ch) && strlen(infgetcws(inpf))))
  664.                 rplc = FALSE;
  665.         }
  666.         if (rplc)
  667.         {
  668.             /* replace ampersand */
  669.             message_rplc(hp, "&", "&");
  670.             set_estr(amp_str, "&");
  671.         }
  672.         else
  673.         {
  674.             /*
  675.              * get entity-id, test for unknown entity
  676.              */
  677.             char *nxtwd;
  678.             DLNODE *nd;
  679.             BOOL app_entity = TRUE;
  680.  
  681.             /* remember "&" */
  682.             set_estr(amp_str, infgetcw(inpf));
  683.  
  684.             /* get entity id */
  685.             nxtwd = infgetw(inpf);
  686.  
  687.             /* TODO: check for white-space */
  688.  
  689.             if (!strcmp(nxtwd, "#"))
  690.             {
  691.                 /*
  692.                  * process numeric entity
  693.                  */
  694.  
  695.                 /* append "#" */
  696.                 app_estr(amp_str, infgetcw(inpf));
  697.  
  698.                 nxtwd = infgetw(inpf);
  699.                 errno = 0;
  700.                 strtoul(nxtwd, NULL, 0);
  701.                 if (errno || strlen(infgetcws(inpf)))
  702.                 {
  703.                     hsc_message(hp, MSG_ILLG_NUM,       /* illegal numeric entity */
  704.                               "illegal numeric value %n for entity", nxtwd);
  705.                 }
  706.                 /* append entity specifier */
  707.                 app_estr(amp_str, nxtwd);
  708.             }
  709.             else
  710.             {
  711.                 /*
  712.                  * process text entity
  713.                  */
  714.  
  715.                 HSCVAR *attr = NULL;
  716.  
  717.                 /* search for entity in list */
  718.                 nd = find_dlnode(hp->defent->first, (APTR) nxtwd, cmp_strent);
  719.  
  720.                 if (hp->jens && (nd == NULL))
  721.                 {
  722.                     /* asume that entity is an attribute,
  723.                      * try to find it and append it's value
  724.                      */
  725.                     attr = find_varname(hp->defattr, nxtwd);
  726.                     if (attr)
  727.                     {
  728.                         set_estr(amp_str, get_vartext(attr));
  729.                         app_entity = FALSE;
  730.                     }
  731.                 }
  732.  
  733.                 if ((nd == NULL) && (attr == NULL))
  734.                 {
  735.                     hsc_message(hp, MSG_UNKN_ENTITY,
  736.                                 "unknown %e", nxtwd);
  737.                 }
  738.                 else
  739.                 {
  740.                     /* check for icon-entity and warn about */
  741.                     /* portability peoblem */
  742.                     HSCENT *entity = dln_data(nd);
  743.  
  744.                     if (entity->numeric == ICON_ENTITY)
  745.                         if (estrlen(hp->iconbase))
  746.                         {
  747.                             replace_icon(hp, nxtwd);
  748.                             set_estr(amp_str, "");
  749.                             app_entity = FALSE;
  750.                         }
  751.                         else
  752.                         {
  753.                             hsc_message(hp, MSG_ICON_ENTITY,
  754.                                         "icon-%e found", nxtwd);
  755.                         }
  756.                 }
  757.  
  758.                 if (app_entity)
  759.                     /* append entity specifier */
  760.                     app_estr(amp_str, nxtwd);
  761.             }
  762.  
  763.             /* TODO: check for whitespace before ";" */
  764.  
  765.             /* check for closing ';' */
  766.             parse_wd(hp, ";");
  767.  
  768.             /* append ";" */
  769.             if (app_entity)
  770.                 app_estr(amp_str, infgetcw(inpf));
  771.         }
  772.  
  773.         /* output whole entity */
  774.         if (estrlen(amp_str))
  775.             hsc_output_text(hp, "", estr2str(amp_str));
  776.  
  777.         del_estr(amp_str);
  778.     }
  779.  
  780.     return (BOOL) (!hp->fatal);
  781. }
  782.  
  783. /*
  784.  * hsc_parse_text
  785.  */
  786. BOOL hsc_parse_text(HSCPRC * hp)
  787. {
  788.     INFILE *inpf = hp->inpf;
  789.     STRPTR nw = infgetcw(inpf);
  790.  
  791.     if (nw && hp->suppress_output && (strcmp(nw, "\n")))
  792.         hp_enable_output(hp, "non-LF text");
  793.  
  794.     if (nw)
  795.     {                           /* do test below only if not end-of-file */
  796.         /*
  797.          * check unmatched ">"
  798.          */
  799.         if (!strcmp(nw, ">"))
  800.         {
  801.             BOOL rplc = hp->smart_ent;  /* TRUE, if ">" should be replaced */
  802.  
  803.             if (rplc)
  804.             {
  805.                 /*
  806.                  * test if char before and
  807.                  * after ">" is white-space
  808.                  */
  809.                 int ch = infgetc(inpf);
  810.  
  811.                 inungetc(ch, inpf);
  812.  
  813.                 if (!(hsc_whtspc(ch) && strlen(infgetcws(inpf))))
  814.                 {
  815.                     rplc = FALSE;
  816.                 }
  817.                 else
  818.                 {
  819.                 };
  820.             }
  821.             if (rplc)
  822.             {
  823.                 /* replace gt */
  824.                 message_rplc(hp, nw, ">");
  825.                 nw = ">";
  826.             }
  827.             else
  828.             {
  829.                 hsc_message(hp, MSG_UNMA_GT,
  830.                             "unmatched \">\"");
  831.             }
  832.         }
  833.         /*
  834.          * check for quote
  835.          */
  836.         else if (!strcmp(nw, "\""))
  837.         {
  838.             if (hp->rplc_quote)
  839.             {
  840.                 /* replace quote */
  841.                 message_rplc(hp, nw, """);
  842.                 nw = """;
  843.             }
  844.         }
  845.         /*
  846.          * check for entities to replace
  847.          */
  848.         else
  849.         {
  850.             DLNODE *nd = NULL;  /* entity search result */
  851.  
  852.             if (hp->rplc_ent && (strlen(nw) == 1) && (nw[0] >= 127))
  853.             {
  854.                 nd = find_dlnode(hp->defent->first, (APTR) nw, cmp_rplcent);
  855.  
  856.                 if (nd)
  857.                 {
  858.                     BOOL ok = TRUE;
  859.  
  860.                     /* copy replaced entity to buffer */
  861.                     ok &= set_estr(hp->tmpstr, "&");
  862.                     ok &= app_estr(hp->tmpstr, ((HSCENT *) nd->data)->name);
  863.                     ok &= app_estr(hp->tmpstr, ";");
  864.  
  865.                     if (ok)
  866.                     {
  867.                         /* replace-message */
  868.                         message_rplc(hp, nw, estr2str(hp->tmpstr));
  869.                         nw = estr2str(hp->tmpstr);
  870.                     }
  871.                 }
  872.             }
  873.             /*
  874.              * check for "click here" syndrome
  875.              */
  876.             if (hp->inside_anchor && hp->click_here_str)
  877.             {
  878.                 ULONG found = strenum(nw, hp->click_here_str, '|', STEN_NOCASE);
  879.                 if (found)
  880.                 {
  881.                     hsc_message(hp, MSG_CLICK_HERE,
  882.                                 "`click here'-syndrome detected");
  883.                 }
  884.             }
  885.         }
  886.     }
  887.  
  888.     if (nw)
  889.         hsc_output_text(hp, "", nw);    /* output word */
  890.  
  891.     return (BOOL) (!hp->fatal);
  892. }
  893.  
  894. /*
  895.  * hsc_parse
  896.  *
  897.  * parse input chars with full hsc support
  898.  *
  899.  * params: inpf...input file
  900.  *
  901.  * result: TRUE, if no error
  902.  */
  903. BOOL hsc_parse(HSCPRC * hp)
  904. {
  905.     if (!hp->fatal)
  906.     {
  907.         STRPTR nxtwd = infgetw(hp->inpf);
  908.  
  909.         /*
  910.          * handle LineFeed: with COMPACT set, write LF without
  911.          * any WhtSpcs and skip any following WhtSpcs. No
  912.          * further parsing on the current word will be done.
  913.          */
  914.         if (nxtwd && (!strcmp(nxtwd, "\n")))
  915.         {
  916.             BOOL suppress_lf = FALSE;
  917.  
  918.             if (!(hp->inside_pre))
  919.             {
  920.                 if (hp->compact)
  921.                 {
  922.                     /* write LF without WhtSpc */
  923.                     hsc_output_text(hp, "", "\n");
  924.  
  925.                     /* skip all followings LFs */
  926.                     skip_lfs(hp);
  927.  
  928.                     /* strip WhtSpcs of next word */
  929.                     infskip_ws(hp->inpf);
  930.  
  931.                     suppress_lf = TRUE;
  932.                 }
  933.             }
  934.             if (!suppress_lf)
  935.             {
  936.                 /* write out LF with WhtSpcs */
  937.                 hsc_output_text(hp, infgetcws(hp->inpf), nxtwd);
  938.             }
  939.             hp->preceding_whtspc = TRUE;
  940.         }
  941.         else
  942.         {
  943.             /* write white spaces */
  944.             STRPTR cws = infgetcws(hp->inpf);   /* current WhtSpcs */
  945.             if (cws)
  946.             {
  947.                 if (!(hp->compact) || (hp->inside_pre))
  948.                 {
  949.                     /* write all WhtSpcs */
  950.                     hsc_output_text(hp, cws, "");
  951.                 }
  952.                 else if (strlen(cws))
  953.                 {
  954.                     /* write single WhtSpc */
  955.                     hsc_output_text(hp, " ", "");
  956.                 }
  957. #if 0
  958.                 else if (cws)
  959.                 {
  960.                     DMSG("no whitespaces to output (len=0)");
  961.                 }
  962.                 else
  963.                 {
  964.                     DMSG("no whitespaces to output (NULL)");
  965.                 }
  966. #endif
  967.  
  968.                 /* check for preceding white-spaces */
  969.                 if (strlen(cws))
  970.                     hp->preceding_whtspc = TRUE;
  971.             }
  972.             /* parse text */
  973.             if (nxtwd)
  974.             {
  975.                 if (!strcmp(nxtwd, "<"))        /* parse tag */
  976.                     hsc_parse_tag(hp);
  977.                 else if (!strcmp(nxtwd, "&"))   /* parse entity */
  978.                     hsc_parse_amp(hp);
  979.                 else
  980.                 {               /* handle text */
  981.                     hsc_parse_text(hp);
  982.                 }
  983.             }
  984.             hp->preceding_whtspc = FALSE;
  985.         }
  986.     }
  987.     return (BOOL) (!hp->fatal);
  988. }
  989.  
  990. /*
  991.  * hsc_parse_source
  992.  *
  993.  * parse input chars with full hsc support
  994.  *
  995.  * params: inpf...input file
  996.  *
  997.  * result: TRUE, if no error
  998.  */
  999. BOOL hsc_parse_source(HSCPRC * hp)
  1000. {
  1001.     if (!hp->fatal)
  1002.     {
  1003.         char *nxtwd = infgetw(hp->inpf);
  1004.  
  1005.         if (nxtwd)
  1006.         {
  1007.             /*
  1008.              * process next word
  1009.              */
  1010.             if (!strcmp(nxtwd, "<"))
  1011.                 hsc_output_text(hp, infgetcws(hp->inpf), "<");
  1012.             else if (!strcmp(nxtwd, ">"))
  1013.                 hsc_output_text(hp, infgetcws(hp->inpf), ">");
  1014.             else if (!strcmp(nxtwd, "&"))
  1015.                 hsc_output_text(hp, infgetcws(hp->inpf), "&");
  1016.             else
  1017.             {
  1018.                 hsc_output_text(hp, infgetcws(hp->inpf), "");
  1019.                 hsc_parse_text(hp);
  1020.             }
  1021.         }
  1022.     }
  1023.     return (BOOL) (!hp->fatal);
  1024. }
  1025.  
  1026. /*
  1027.  *---------------------------
  1028.  * parse end functions
  1029.  *---------------------------
  1030.  */
  1031.  
  1032. /*
  1033.  * hsc_parse_end
  1034.  *
  1035.  * check for all tags closed and required
  1036.  * tags occured
  1037.  */
  1038. BOOL hsc_parse_end(HSCPRC * hp)
  1039. {
  1040.     if (!hp->fatal)
  1041.     {
  1042.         INFILEPOS *infpos = new_infilepos(hp->inpf);
  1043.  
  1044.         /* check for unclosed containers */
  1045.         DLNODE *nd = hp->container_stack->first;
  1046.         while (nd)
  1047.         {
  1048.             HSCTAG *endtag = (HSCTAG *) dln_data(nd);
  1049.  
  1050.             set_infilepos(hp->inpf, endtag->start_fpos);
  1051.             hsc_message(hp, MSG_MISS_CTAG,
  1052.                         "%c missing", endtag->name);
  1053.  
  1054.             nd = dln_next(nd);
  1055.         }
  1056.  
  1057.         set_infilepos(hp->inpf, infpos);
  1058.         del_infilepos(infpos);
  1059.  
  1060.         /* check for required tags missing */
  1061.         nd = hp->deftag->first;
  1062.         while (nd)
  1063.         {
  1064.             HSCTAG *tag = (HSCTAG *) nd->data;
  1065.  
  1066.             if ((tag->option & HT_REQUIRED
  1067.                  && (tag->occured == FALSE)))
  1068.             {
  1069.                 hsc_message(hp, MSG_MISS_REQTAG,
  1070.                             "required %T missing", tag);
  1071.             }
  1072.             nd = nd->next;
  1073.         }
  1074.     }
  1075.     return (BOOL) (!hp->fatal);
  1076. }
  1077.  
  1078. /*
  1079.  *---------------------------
  1080.  * parse IDs functions
  1081.  *---------------------------
  1082.  */
  1083.  
  1084. /*
  1085.  * hsc_parse_end_id
  1086.  *
  1087.  * append all locally defined IDs to global IDs,
  1088.  * check all before referenced local IDs
  1089.  *
  1090.  */
  1091. BOOL hsc_parse_end_id(HSCPRC * hp)
  1092. {
  1093.     if (!hp->fatal)
  1094.         check_all_local_idref(hp);      /* check local IDs */
  1095.  
  1096.     return (BOOL) (!hp->fatal);
  1097. }
  1098.  
  1099.